package com.hmdp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Autowired
    private ISeckillVoucherService seckillVoucherService;
    @Autowired
    private RedisIdWorker redisIdWorker;
    @Autowired
    private RedissonClient redissonClient;

    //抢购秒杀优惠券
    @Override
    public Result seckillVoucher(Long voucherId) {
        //1.根据优惠券id查询优惠券信息
        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
        //2. 根据秒杀券的时间判断秒杀是否开始和结束
        if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())
                || seckillVoucher.getEndTime().isBefore(LocalDateTime.now())) {
            //秒杀尚未开始或已经结束
            return Result.fail("秒杀尚未开始或已经结束");
        }
        //3.查看库存容量
        if (seckillVoucher.getStock() < 1) {
            //库存不足
            return Result.fail("库存不足");
        }
        Long UserId = UserHolder.getUser().getId();
        //创建锁对象
        RLock lock = redissonClient.getLock("lock:order:" + UserId);
        boolean isLock = lock.tryLock();  //无参 失败不等待
        if(!isLock){
            return Result.fail("请勿重复下单");
        }try {
            //获取代理对象（事务）
            IVoucherOrderService proxy =(IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);   //为什么要用锁呢 因为假如多个线程的同一用户都在执行查询操作 都查到count=0 此时会出现同一用户超卖的情况
        }finally {
            //释放锁
            lock.unlock();
        }
    }

    @Transactional
    public Result createVoucherOrder(Long voucherId) {
        //4.一人一单
        Long UserId = UserHolder.getUser().getId();
        //Long count = query().eq("user_id", UserId).eq("voucher_id", voucherId).count();
        LambdaQueryWrapper<VoucherOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VoucherOrder::getUserId, UserId);
        queryWrapper.eq(VoucherOrder::getVoucherId, voucherId);
        Long count = count(queryWrapper);
        if (count > 0) {
            //用户已经购买过
            return Result.fail("用户已经购买过");
        }
        //5.扣减库存
        //boolean success = seckillVoucherService.update().setSql("stock = stock - 1").eq("voucher_id", voucherId).gt("stock", 0).update();
        //乐观锁解决库存超卖的问题
        LambdaUpdateWrapper<SeckillVoucher> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.setSql("stock = stock - 1");
        updateWrapper.eq(SeckillVoucher::getVoucherId, voucherId);
        updateWrapper.gt(SeckillVoucher::getStock, 0);
        boolean success = seckillVoucherService.update(updateWrapper);
        if (!success) {
            return Result.fail("库存不足");
        }
        //6.创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //获取用户id
        voucherOrder.setUserId(UserId);
        //获取订单id
        Long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        //获取优惠券id
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        //7.返回订单id
        return Result.ok(orderId);
    }
}
